﻿using DeHeng_Mes.Dao;
using DeHeng_Mes.Model.ConfigModel;
using DeHeng_Mes.Model.Singleton;
using DeHeng_Mes.Model.Table;
using DeHeng_Mes.Utils;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using S7.Net;

namespace DeHeng_Mes.Thread
{
    public  class ErrorGather
    {
        /// <summary>
        /// 采集报警信息
        /// </summary>
        public async Task GetError()
        {
            ErrorDao errorDao = new ErrorDao();
            Tools.ProduceLogText("启动报警信息采集");
            while (true)
            {
                try
                {
                    List<PlcOrderConfigModel> readPlcList = PlcOrderConfigModelList.ReadPlcList.Where(x => x.plc.IsConnected == true).ToList();

                    foreach (var item in readPlcList)
                    {
                        byte[] bytes = item.plc.ReadBytes(DataType.DataBlock, 5110, 0, 68);

                        // 处理bool报警
                        for (int i = 0; i < bytes.Length; i++)
                        {
                            if (i >= 2 && i <= 20)
                            {
                                if (i % 2 == 0)
                                {
                                    int status = S7.Net.Types.Word.FromByteArray(bytes.Skip(i).Take(2).ToArray());

                                    (string errorType, string errorMessage) = MappingTable.GetErrorMessage(i, 0);

                                    // 存在报警,先获取对应的报警文本
                                    if (string.IsNullOrEmpty(errorMessage))
                                        continue;

                                    IReadOnlyDictionary<int, string> readOnlyDictionary = ErrorDic.GetAllAlarms();

                                    // 1.到全局缓存中查找有报警信息
                                    bool isExit = IsExist(errorMessage);

                                    if (status == 1 && !isExit)
                                    {
                                        // 2.缓存有报警信息就跳过，没有报警信息存储数据库记录开始时间并且全局缓存报警，记录缓存时候带上数据库主键
                                        DeviceFault deviceFault = new DeviceFault()
                                        {

                                            PlcName = item.PlcName,

                                            FaultType = errorType,

                                            FaultMessage = errorMessage,

                                            StopStartTime = DateTime.Now,
                                        };

                                        int id = errorDao.insertError(deviceFault);

                                        ErrorDic.AddAlarm(id, errorMessage);

                                        Tools.ProduceLogText($"添加了一条报警信息到缓存中，报警信息为{deviceFault.FaultMessage}");
                                    }
                                    else if (status == 0 && isExit)
                                    {
                                        // 1.到全局缓存找有没有当前报警缓存，有就根据主键更新数据库中结束时间并且清除当前一条缓存，没有就跳过
                                        int id = ErrorDic.GetAlarmIdByMessage(errorMessage);

                                        if (id != 0)
                                        {
                                            // 更新数据库结束时间
                                            errorDao.updateError(DateTime.Now, id);

                                            // 从缓存移除
                                            ErrorDic.RemoveAlarm(id);

                                            Tools.ProduceLogText($"从缓存中移除了一条报警信息，报警缓存id为{id}，报警信息为{errorMessage}");
                                        }
                                    }
                                }
                            }
                            else
                            {
                                for (int j = 0; j < 8; j++)
                                {
                                    bool isError = S7.Net.Types.Bit.FromByte(bytes[i], (byte)j);

                                    (string errorType, string errorMessage) = MappingTable.GetErrorMessage(i, j);

                                    bool isExit = IsExist(errorMessage);

                                    if (isError && !isExit)
                                    {
                                        // 存在报警,先获取对应的报警文本
                                        if (string.IsNullOrEmpty(errorMessage))
                                            continue;

                                        // 2.缓存有报警信息就跳过，没有报警信息存储数据库记录开始时间并且全局缓存报警，记录缓存时候带上数据库主键
                                        DeviceFault deviceFault = new DeviceFault()
                                        {

                                            PlcName = item.PlcName,

                                            FaultType = errorType,

                                            FaultMessage = errorMessage,

                                            StopStartTime = DateTime.Now,
                                        };

                                        int id = errorDao.insertError(deviceFault);

                                        ErrorDic.AddAlarm(id, errorMessage);

                                        Tools.ProduceLogText($"添加了一条报警信息到缓存中，报警信息为{deviceFault.FaultMessage}");
                                    }
                                    else if (!isError && isExit)
                                    {
                                        // 1.到全局缓存找有没有当前报警缓存，有就根据主键更新数据库中结束时间并且清除当前一条缓存，没有就跳过
                                        int id = ErrorDic.GetAlarmIdByMessage(errorMessage);

                                        if (id != 0)
                                        {
                                            // 更新数据库结束时间
                                            errorDao.updateError(DateTime.Now, id);

                                            // 从缓存移除
                                            ErrorDic.RemoveAlarm(id);

                                            Tools.ProduceLogText($"从缓存中移除了一条报警信息，报警缓存id为{id}，报警信息为{errorMessage}");
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
                catch (Exception ex)
                {
                    Tools.ProduceLogText($"采集报警信息失败，原因为{ex.Message}");
                }

                await Task.Delay(1000);
            }
        }
        /// <summary>
        /// 判断报警是否存在于缓存数据中
        /// </summary>
        /// <param name="message"></param>
        /// <returns></returns>
        private bool IsExist(string message)
        {
            return ErrorDic.GetAllAlarms().Values.Contains(message);
        }
    }
}
